package de.oszimtcc.googleapi;

import java.io.IOException;
import java.util.List;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;

import com.google.api.client.extensions.android2.AndroidHttp;
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.googleapis.services.GoogleKeyInitializer;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.calendar.model.Event;
import com.google.common.collect.Lists;

import de.oszimtcc.framework.BaseActivity;
import de.oszimtcc.timetable.TimetableApplication;

/**
 * @author reuter
 * 
 */
public class AppointmentReader
{
	private static final String	AUTH_TOKEN_TYPE = "cl";
	private String KEY = "AIzaSyAmunOoPNWrtxQvd3vjeuWyOCHFmaC95l0";
	private static final int REQUEST_AUTHENTICATE = 0;	
	private static final String PREF_ACCOUNT_NAME = "accountName";
	private static final String PREF_AUTH_TOKEN = "authToken";
	private final HttpTransport	transport = AndroidHttp.newCompatibleTransport();
	private final JsonFactory jsonFactory = new GsonFactory();
	private BaseActivity activity = TimetableApplication.getInstance().getActivity();
	private AppointmentListView dataPresenter;
	private GoogleAccountManager accountManager;
	private String accountName;
	private String authToken;
	public com.google.api.services.calendar.Calendar client;
	public List<CalendarInfo> calendars = Lists.newArrayList();
	private boolean received401;
	private HttpRequestInitializer initializer = new HttpRequestInitializer() 
	{
		
		public void initialize(HttpRequest request) throws IOException
		{
			request.getHeaders().setAuthorization(GoogleHeaders.getGoogleLoginValue(authToken));
		}
	};

	public AppointmentReader()
	{
		client = com.google.api.services.calendar.Calendar.builder(transport, jsonFactory)
		.setApplicationName("OSZIMT-Timetable")
		.setHttpRequestInitializer(initializer)
		.setJsonHttpRequestInitializer(new GoogleKeyInitializer(KEY))
		.build();

		accountName = activity.GetStringPreference(PREF_ACCOUNT_NAME);
		authToken = activity.GetStringPreference(PREF_AUTH_TOKEN);
		accountManager = new GoogleAccountManager(TimetableApplication.getInstance().getActivity());
		gotAccount();
	}
	
	public AppointmentReader(AppointmentListView pDataPresenter)
	{
		dataPresenter = pDataPresenter;
		client = com.google.api.services.calendar.Calendar.builder(transport, jsonFactory).setApplicationName("OSZIMT-Timetable")
			.setHttpRequestInitializer(new HttpRequestInitializer() 
				{
		
					public void initialize(HttpRequest request) throws IOException
					{
						request.getHeaders().setAuthorization(GoogleHeaders.getGoogleLoginValue(authToken));
					}
				})
			.setJsonHttpRequestInitializer(new GoogleKeyInitializer(KEY))
			.build();

		accountName = activity.GetStringPreference(PREF_ACCOUNT_NAME);
		authToken = activity.GetStringPreference(PREF_AUTH_TOKEN);
		accountManager = new GoogleAccountManager(TimetableApplication.getInstance().getActivity());
		gotAccount();
	}

	void gotAccount()
	{
		Account account = accountManager.getAccountByName(accountName);
		if(account == null)
		{
			chooseAccount();
			return;
		}
		if(authToken != null)
		{
			onAuthToken();
			return;
		}
		
		accountManager.getAccountManager().getAuthToken(account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>() 
		{
			public void run(AccountManagerFuture<Bundle> future)
			{
				try
				{
					Bundle bundle = future.getResult();
					if(bundle.containsKey(AccountManager.KEY_INTENT))
					{
						Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
						intent.setFlags(intent.getFlags() & ~ Intent.FLAG_ACTIVITY_NEW_TASK);
						activity.startActivityForResult(intent, REQUEST_AUTHENTICATE);
					}
					else
					{
						if(bundle.containsKey(AccountManager.KEY_AUTHTOKEN))
						{
							setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN));
							onAuthToken();
						}
					}
				}
				catch(Exception e)
				{
				}
			}
		}, null);
	}

	private void chooseAccount()
	{
		accountManager.getAccountManager().getAuthTokenByFeatures(GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null, activity, null, null, new AccountManagerCallback<Bundle>() {

			public void run(AccountManagerFuture<Bundle> future)
			{
				Bundle bundle;
				try
				{
					bundle = future.getResult();
					setAccountName(bundle.getString(AccountManager.KEY_ACCOUNT_NAME));
					setAuthToken(bundle.getString(AccountManager.KEY_AUTHTOKEN));
					onAuthToken();
				}
				catch(OperationCanceledException e)
				{
				}
				catch(AuthenticatorException e)
				{
				}
				catch(IOException e)
				{
				}
			}
		}, null);
	}

	void setAccountName(String accountName)
	{
		activity.SetStringPreference(PREF_ACCOUNT_NAME, accountName);
		this.accountName = accountName;
	}

	void setAuthToken(String authToken)
	{
		activity.SetStringPreference(PREF_AUTH_TOKEN, authToken);
		this.authToken = authToken;
	}

	public void onAuthToken()
	{
		new LoadEventsAsync(this).execute();
	}
	
	void onNewEventFound(Event pNewEvent)
	{
		if(dataPresenter != null)
		{
			dataPresenter.addListEntry(pNewEvent);
		}
	}

	void onRequestCompleted()
	{
		received401 = false;
	}

	void handleGoogleException(final IOException e)
	{
		if(e instanceof GoogleJsonResponseException)
		{
			GoogleJsonResponseException exception = (GoogleJsonResponseException)e;
			if(exception.getStatusCode() == 401 && ! received401)
			{
				received401 = true;
				accountManager.invalidateAuthToken(authToken);
				authToken = null;
				gotAccount();
			}
		}
		activity.runOnUiThread(new Runnable() 
		{

			public void run()
			{
				new AlertDialog.Builder(activity).setTitle("Exception").setMessage(e.getMessage()).setNeutralButton("ok", null).create().show();
			}
		});
	}
}
